﻿// --------------------------------
// <copyright file="Textbox.cs" company="Faculty of Information Technology, Czech Technical University in Prague">
//     This document is shared by Microsoft Public License (MS-PL)
//     For further details please see http://msdn.microsoft.com/en-us/library/ff648068.aspx or license.txt.
// </copyright>
// <author>Lukáš Molnár</author>

// <email>molnaluk@fit.cvut.cz</email>

// <date>9. 11. 2011 22:22:37</date>

// <summary>
//
// </summary>
// --------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

#if WINDOWS

using System.ComponentModel;
using FITClub.TextureMenu.Configuration;
using System.Drawing.Design;
using FITClub.Episode1.Levels;

#endif

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using System.Xml.Serialization;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.GamerServices;

namespace FITClub.TextureMenu
{
#if WINDOWS

    [System.Serializable]
#endif
    /// <summary>
    /// From keyborad input composes string.
    /// </summary>
    public class Textbox : AMenuItem, IUpdateableItem
    {
        #region Public properties

#if WINDOWS

        [Category("Path")]
        [Editor(typeof(ContentPathEditor), typeof(UITypeEditor))]
        [EditorBrowsable(EditorBrowsableState.Always)]
#endif
        [XmlAttribute]
        public string FontPath { get; set; }

        [XmlElement]
#if WINDOWS
        [Category("Content")]
#endif
        public string Text { get; set; }

        [XmlElement]
#if WINDOWS
        [Category("Colors")]
        [Editor(typeof(ColorEditor), typeof(UITypeEditor))]
        [EditorBrowsable(EditorBrowsableState.Always)]
#endif
        public Color TextColor { get; set; }

        /// <summary>
        /// Maximum count of characters,
        /// </summary>
        [XmlAttribute]
        public int MaxLength { get; set; }

        #endregion Public properties

        #region Private fields

#if WINDOWS
        [System.NonSerialized]
#endif
        private Texture2D Cursor;

#if WINDOWS
        [System.NonSerialized]
#endif
        private Texture2D Farme;
        private int cursorPosition;
        private string lastChar;
        private bool editMode;

#if WINDOWS
        [System.NonSerialized]
#endif
        private IAsyncResult keyboardResult;

#if WINDOWS
        [System.NonSerialized]
#endif
        private SpriteFont font;

        #endregion Private fields

        public override void LoadContent(ContentManager loader)
        {
            if (this.ContentLoaded == false)
            {
                this.cursorPosition = this.Text.Length;
                Cursor = loader.Load<Texture2D>("menu\\textbox_cursor");
                this.Farme = loader.Load<Texture2D>("menu\\textbox_frame");
                this.font = MenuHelper.LoadFontOrDefault(loader, this.FontPath);
                this.ContentLoaded = true;
            }
        }

        public override void ItemSelected()
        {
            editMode = true;
            cursorPosition = Text.Length;
#if WINDOWS_PHONE
            keyboardResult = Guide.BeginShowKeyboardInput(PlayerIndex.One, "Enter Player Name", "Player Name", this.Text, this.GetInputText, null);
#endif
        }

        protected void GetInputText(IAsyncResult r)
        {
            string text = Guide.EndShowKeyboardInput(r);
            if (text != null && text.Trim() != string.Empty)
            {
                if (text.Length > this.MaxLength)
                {
                    text = text.Substring(0, this.MaxLength);
                }
                this.Text = text;
                this.cursorPosition = text.Length;
            }
        }

        public override void ItemLeft()
        {
            editMode = false;
        }

        public override void Dispose()
        {
            if (ContentLoaded)
            {
                Cursor.Dispose();
                this.ContentLoaded = false;
            }
        }

        public override void Draw(SpriteBatch spriteBatch, Color tint)
        {
            if (this.IsSelected)
            {
                MenuHelper.DrawBorder(spriteBatch, this.Bounds, Owner.SelectedItemBackground, 4);
            }

            Rectangle textRect = new Rectangle(this.Bounds.X + 3, this.Bounds.Y + 3, this.Bounds.Width - 6, this.Bounds.Height - 6);
            spriteBatch.Draw(this.Farme, this.Bounds, tint);

            if (this.IsSelected)
            {
                if (cursorPosition > Text.Length)
                {
                    this.cursorPosition = this.Text.Length;
                }
                MenuHelper.DrawText(spriteBatch, font, this.Text, this.TextColor, textRect, TextAlignment.Left, this.Resizable);
                int width = (int)Math.Ceiling(font.MeasureString(this.Text.Substring(0, cursorPosition)).X * MenuManager.ScaleY);
                spriteBatch.Draw(this.Cursor, new Rectangle(textRect.X + width, textRect.Y, (int)(this.Cursor.Width * MenuManager.ScaleX), textRect.Height), tint);
            }
            else
            {
                string displayText;
                int length = this.Text.Length;
                Vector2 textsize;
                do
                {
                    displayText = this.Text.Substring(0, length--);
                    textsize = font.MeasureString(displayText);
                } while (textsize.X > textRect.Width);
                MenuHelper.DrawText(spriteBatch, font, displayText, this.TextColor, textRect, TextAlignment.Left, this.Resizable);
            }
        }

        public void EditAction()
        {
            editMode = !editMode;
            if (editMode)
            {
            }
        }

        public void Update(GameTime gt)
        {
#if WINDOWS == false
            if ( MenuManager.Current.MouseUpTest(this.Bounds))
            {
                keyboardResult = Guide.BeginShowKeyboardInput(PlayerIndex.One, "Enter Player Name", "Player Name", this.Text, this.GetInputText, null);
                return;
            }
#endif
            if (IsSelected == false) return;
            if (MenuManager.Current.HitTest(Keys.Left, 11))
            {
                if (cursorPosition > 0) cursorPosition--;
                return;
            }
            else
            {
                if (MenuManager.Current.HitTest(Keys.Right, 11))
                {
                    if (cursorPosition < this.Text.Length) cursorPosition++;
                    return;
                }
                else
                {
                    if (MenuManager.Current.HitTest(Keys.Back, 11))
                    {
                        if (cursorPosition > 0)
                        {
                            cursorPosition--;
                            this.Text = this.Text.Remove(cursorPosition, 1);
                        }
                        return;
                    }
                    else
                    {
                        if (MenuManager.Current.HitTest(Keys.Delete, 11))
                        {
                            if (cursorPosition < this.Text.Length)
                            {
                                this.Text = this.Text.Remove(cursorPosition, 1);
                            }
                            return;
                        }
                    }
                }
            }

            /// length check
            if (this.Text.Length >= this.MaxLength) return;

            Keys[] pressed = MenuManager.Current.ActualKeyboardState.GetPressedKeys();
            Keys txt = Keys.None;
            bool shift = false;
            foreach (var item in pressed)
            {
                if (item != Keys.CapsLock && item != Keys.LeftShift && Keys.RightShift != item)
                {
                    txt = item;
                }
                if (item == Keys.RightShift || item == Keys.LeftShift)
                {
                    shift = true;
                }
            }
            string ch = ConvertKeyToChar(txt, shift);
            if (ch.Length > 0)
            {
                if (ch != lastChar || MenuManager.Current.cycles > 11)
                {
                    this.Text = this.Text.Insert(this.cursorPosition, ch);
                    cursorPosition++;
                    MenuManager.Current.cycles = 0;
                    lastChar = ch;
                }
            }
        }

        public static string ConvertKeyToChar(Keys key, bool shift)
        {
            switch (key)
            {
                case Keys.Space: return " ";

                // D-Numerics (strip above the alphabet)
                case Keys.D0: return shift ? ")" : "0";
                case Keys.D1: return shift ? "!" : "1";
                case Keys.D2: return shift ? "@" : "2";
                case Keys.D3: return shift ? "#" : "3";
                case Keys.D4: return shift ? "$" : "4";
                case Keys.D5: return shift ? "%" : "5";
                case Keys.D6: return shift ? "^" : "6";
                case Keys.D7: return shift ? "&" : "7";
                case Keys.D8: return shift ? "*" : "8";
                case Keys.D9: return shift ? "(" : "9";

                // Numpad
                case Keys.NumPad0: return "0";
                case Keys.NumPad1: return "1";
                case Keys.NumPad2: return "2";
                case Keys.NumPad3: return "3";
                case Keys.NumPad4: return "4";
                case Keys.NumPad5: return "5";
                case Keys.NumPad6: return "6";
                case Keys.NumPad7: return "7";
                case Keys.NumPad8: return "8";
                case Keys.NumPad9: return "9";
                case Keys.Add: return "+";
                case Keys.Subtract: return "-";
                case Keys.Multiply: return "*";
                case Keys.Divide: return "/";
                case Keys.Decimal: return ".";

                // Alphabet
                case Keys.A: return shift ? "A" : "a";
                case Keys.B: return shift ? "B" : "b";
                case Keys.C: return shift ? "C" : "c";
                case Keys.D: return shift ? "D" : "d";
                case Keys.E: return shift ? "E" : "e";
                case Keys.F: return shift ? "F" : "f";
                case Keys.G: return shift ? "G" : "g";
                case Keys.H: return shift ? "H" : "h";
                case Keys.I: return shift ? "I" : "i";
                case Keys.J: return shift ? "J" : "j";
                case Keys.K: return shift ? "K" : "k";
                case Keys.L: return shift ? "L" : "l";
                case Keys.M: return shift ? "M" : "m";
                case Keys.N: return shift ? "N" : "n";
                case Keys.O: return shift ? "O" : "o";
                case Keys.P: return shift ? "P" : "p";
                case Keys.Q: return shift ? "Q" : "q";
                case Keys.R: return shift ? "R" : "r";
                case Keys.S: return shift ? "S" : "s";
                case Keys.T: return shift ? "T" : "t";
                case Keys.U: return shift ? "U" : "u";
                case Keys.V: return shift ? "V" : "v";
                case Keys.W: return shift ? "W" : "w";
                case Keys.X: return shift ? "X" : "x";
                case Keys.Y: return shift ? "Y" : "y";
                case Keys.Z: return shift ? "Z" : "z";

                // Oem
                case Keys.OemOpenBrackets: return shift ? "{" : "[";
                case Keys.OemCloseBrackets: return shift ? "}" : "]";
                case Keys.OemComma: return shift ? "<" : ",";
                case Keys.OemPeriod: return shift ? ">" : ".";
                case Keys.OemMinus: return shift ? "_" : "-";
                case Keys.OemPlus: return shift ? "+" : "=";
                case Keys.OemQuestion: return shift ? "?" : "/";
                case Keys.OemSemicolon: return shift ? ":" : ";";
                case Keys.OemQuotes: return shift ? "\"" : "'";
                case Keys.OemPipe: return shift ? "|" : "\\";
                case Keys.OemTilde: return shift ? "~" : "`";
            }

            return string.Empty;
        }
    }
}